home *** CD-ROM | disk | FTP | other *** search
- /* $Id: mipmap.c,v 1.1 1996/09/27 01:19:39 brianp Exp $ */
-
- /*
- * Mesa 3-D graphics library
- * Version: 2.0
- * Copyright (C) 1995-1996 Brian Paul
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free
- * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-
- /*
- * $Log: mipmap.c,v $
- * Revision 1.1 1996/09/27 01:19:39 brianp
- * Initial revision
- *
- */
-
-
- #include <assert.h>
- #include <math.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include "gluP.h"
-
-
-
- /*
- * Compute ceiling of integer quotient of A divided by B:
- */
- #define CEILING( A, B ) ( (A) % (B) == 0 ? (A)/(B) : (A)/(B)+1 )
-
-
-
- #define EPSILON 0.001
-
-
-
-
- GLint gluScaleImage( GLenum format,
- GLint widthin, GLint heightin,
- GLenum typein, const void *datain,
- GLint widthout, GLint heightout,
- GLenum typeout, void *dataout )
- {
- GLuint components, i, j, k;
- GLfloat *tempin, *tempout;
- GLfloat sx, sy;
- GLint unpackrowlength, unpackalignment, unpackskiprows, unpackskippixels;
- GLint packrowlength, packalignment, packskiprows, packskippixels;
- GLint sizein, sizeout;
- GLint rowstride, rowlen;
-
-
- /* Determine number of components per pixel */
- switch (format) {
- case GL_COLOR_INDEX:
- case GL_STENCIL_INDEX:
- case GL_DEPTH_COMPONENT:
- case GL_RED:
- case GL_GREEN:
- case GL_BLUE:
- case GL_ALPHA:
- case GL_LUMINANCE:
- components = 1;
- break;
- case GL_LUMINANCE_ALPHA:
- components = 2;
- break;
- case GL_RGB:
- components = 3;
- break;
- case GL_RGBA:
- components = 4;
- break;
- default:
- return GLU_INVALID_ENUM;
- }
-
- /* Determine bytes per input datum */
- switch (typein) {
- case GL_UNSIGNED_BYTE: sizein = sizeof(GLubyte); break;
- case GL_BYTE: sizein = sizeof(GLbyte); break;
- case GL_UNSIGNED_SHORT: sizein = sizeof(GLushort); break;
- case GL_SHORT: sizein = sizeof(GLshort); break;
- case GL_UNSIGNED_INT: sizein = sizeof(GLuint); break;
- case GL_INT: sizein = sizeof(GLint); break;
- case GL_FLOAT: sizein = sizeof(GLfloat); break;
- case GL_BITMAP:
- /* not implemented yet */
- default:
- return GL_INVALID_ENUM;
- }
-
- /* Determine bytes per output datum */
- switch (typeout) {
- case GL_UNSIGNED_BYTE: sizeout = sizeof(GLubyte); break;
- case GL_BYTE: sizeout = sizeof(GLbyte); break;
- case GL_UNSIGNED_SHORT: sizeout = sizeof(GLushort); break;
- case GL_SHORT: sizeout = sizeof(GLshort); break;
- case GL_UNSIGNED_INT: sizeout = sizeof(GLuint); break;
- case GL_INT: sizeout = sizeof(GLint); break;
- case GL_FLOAT: sizeout = sizeof(GLfloat); break;
- case GL_BITMAP:
- /* not implemented yet */
- default:
- return GL_INVALID_ENUM;
- }
-
- /* Get glPixelStore state */
- glGetIntegerv( GL_UNPACK_ROW_LENGTH, &unpackrowlength );
- glGetIntegerv( GL_UNPACK_ALIGNMENT, &unpackalignment );
- glGetIntegerv( GL_UNPACK_SKIP_ROWS, &unpackskiprows );
- glGetIntegerv( GL_UNPACK_SKIP_PIXELS, &unpackskippixels );
- glGetIntegerv( GL_PACK_ROW_LENGTH, &packrowlength );
- glGetIntegerv( GL_PACK_ALIGNMENT, &packalignment );
- glGetIntegerv( GL_PACK_SKIP_ROWS, &packskiprows );
- glGetIntegerv( GL_PACK_SKIP_PIXELS, &packskippixels );
-
- /* Allocate storage for intermediate images */
- tempin = (GLfloat *) malloc( widthin * heightin
- * components * sizeof(GLfloat) );
- if (!tempin) {
- return GLU_OUT_OF_MEMORY;
- }
- tempout = (GLfloat *) malloc( widthout * heightout
- * components * sizeof(GLfloat) );
- if (!tempout) {
- free( tempin );
- return GLU_OUT_OF_MEMORY;
- }
-
-
- /*
- * Unpack the pixel data and convert to floating point
- */
-
- if (unpackrowlength>0) {
- rowlen = unpackrowlength;
- }
- else {
- rowlen = widthin;
- }
- if (sizein >= unpackalignment) {
- rowstride = components * rowlen;
- }
- else {
- rowstride = unpackalignment/sizein
- * CEILING( components * rowlen * sizein, unpackalignment );
- }
-
- switch (typein) {
- case GL_UNSIGNED_BYTE:
- k = 0;
- for (i=0;i<heightin;i++) {
- GLubyte *ubptr = (GLubyte *) datain
- + i * rowstride
- + unpackskiprows * rowstride
- + unpackskippixels * components;
- for (j=0;j<widthin*components;j++) {
- tempin[k++] = (GLfloat) *ubptr++;
- }
- }
- break;
- case GL_BYTE:
- k = 0;
- for (i=0;i<heightin;i++) {
- GLbyte *bptr = (GLbyte *) datain
- + i * rowstride
- + unpackskiprows * rowstride
- + unpackskippixels * components;
- for (j=0;j<widthin*components;j++) {
- tempin[k++] = (GLfloat) *bptr++;
- }
- }
- break;
- case GL_UNSIGNED_SHORT:
- k = 0;
- for (i=0;i<heightin;i++) {
- GLushort *usptr = (GLushort *) datain
- + i * rowstride
- + unpackskiprows * rowstride
- + unpackskippixels * components;
- for (j=0;j<widthin*components;j++) {
- tempin[k++] = (GLfloat) *usptr++;
- }
- }
- break;
- case GL_SHORT:
- k = 0;
- for (i=0;i<heightin;i++) {
- GLshort *sptr = (GLshort *) datain
- + i * rowstride
- + unpackskiprows * rowstride
- + unpackskippixels * components;
- for (j=0;j<widthin*components;j++) {
- tempin[k++] = (GLfloat) *sptr++;
- }
- }
- break;
- case GL_UNSIGNED_INT:
- k = 0;
- for (i=0;i<heightin;i++) {
- GLuint *uiptr = (GLuint *) datain
- + i * rowstride
- + unpackskiprows * rowstride
- + unpackskippixels * components;
- for (j=0;j<widthin*components;j++) {
- tempin[k++] = (GLfloat) *uiptr++;
- }
- }
- break;
- case GL_INT:
- k = 0;
- for (i=0;i<heightin;i++) {
- GLint *iptr = (GLint *) datain
- + i * rowstride
- + unpackskiprows * rowstride
- + unpackskippixels * components;
- for (j=0;j<widthin*components;j++) {
- tempin[k++] = (GLfloat) *iptr++;
- }
- }
- break;
- case GL_FLOAT:
- k = 0;
- for (i=0;i<heightin;i++) {
- GLfloat *fptr = (GLfloat *) datain
- + i * rowstride
- + unpackskiprows * rowstride
- + unpackskippixels * components;
- for (j=0;j<widthin*components;j++) {
- tempin[k++] = *fptr++;
- }
- }
- break;
- default:
- return GLU_INVALID_ENUM;
- }
-
-
- /*
- * Scale the image!
- */
-
- sx = (GLfloat) widthin / (GLfloat) widthout;
- sy = (GLfloat) heightin / (GLfloat) heightout;
-
- /*#define POINT_SAMPLE*/
- #ifdef POINT_SAMPLE
- for (i=0;i<heightout;i++) {
- GLint ii = i * sy;
- for (j=0;j<widthout;j++) {
- GLint jj = j * sx;
-
- GLfloat *src = tempin + (ii * widthin + jj) * components;
- GLfloat *dst = tempout + (i * widthout + j) * components;
-
- for (k=0;k<components;k++) {
- *dst++ = *src++;
- }
- }
- }
- #else
- if (sx<1.0 && sy<1.0) {
- /* magnify both width and height: use weighted sample of 4 pixels */
- GLint i0, i1, j0, j1;
- GLfloat alpha, beta;
- GLfloat *src00, *src01, *src10, *src11;
- GLfloat s1, s2;
- GLfloat *dst;
-
- for (i=0;i<heightout;i++) {
- i0 = i * sy;
- i1 = (i+1) * sy - EPSILON;
- alpha = i*sy - i0;
- for (j=0;j<widthout;j++) {
- j0 = j * sx;
- j1 = (j+1) * sx - EPSILON;
- beta = j*sx - j0;
-
- /* compute weighted average of pixels in rect (i0,j0)-(i1,j1) */
- src00 = tempin + (i0 * widthin + j0) * components;
- src01 = tempin + (i0 * widthin + j1) * components;
- src10 = tempin + (i1 * widthin + j0) * components;
- src11 = tempin + (i1 * widthin + j1) * components;
-
- dst = tempout + (i * widthout + j) * components;
-
- for (k=0;k<components;k++) {
- s1 = *src00++ * (1.0-beta) + *src01++ * beta;
- s2 = *src10++ * (1.0-beta) + *src11++ * beta;
- *dst++ = s1 * (1.0-alpha) + s2 * alpha;
- }
- }
- }
- }
- else {
- /* shrink width and/or height: use an unweighted box filter */
- GLint i0, i1;
- GLint j0, j1;
- GLint ii, jj;
- GLfloat sum, *dst;
-
- for (i=0;i<heightout;i++) {
- i0 = i * sy;
- i1 = (i+1) * sy - EPSILON;
- for (j=0;j<widthout;j++) {
- j0 = j * sx;
- j1 = (j+1) * sx - EPSILON;
-
- dst = tempout + (i * widthout + j) * components;
-
- /* compute average of pixels in the rectangle (i0,j0)-(i1,j1) */
- for (k=0;k<components;k++) {
- sum = 0.0;
- for (ii=i0;ii<=i1;ii++) {
- for (jj=j0;jj<=j1;jj++) {
- sum += *(tempin + (ii * widthin + jj) * components + k);
- }
- }
- sum /= (j1-j0+1) * (i1-i0+1);
- *dst++ = sum;
- }
- }
- }
- }
- #endif
-
-
- /*
- * Return output image
- */
-
- if (packrowlength>0) {
- rowlen = packrowlength;
- }
- else {
- rowlen = widthout;
- }
- if (sizeout >= packalignment) {
- rowstride = components * rowlen;
- }
- else {
- rowstride = packalignment/sizeout
- * CEILING( components * rowlen * sizeout, packalignment );
- }
-
- switch (typeout) {
- case GL_UNSIGNED_BYTE:
- k = 0;
- for (i=0;i<heightout;i++) {
- GLubyte *ubptr = (GLubyte *) dataout
- + i * rowstride
- + packskiprows * rowstride
- + packskippixels * components;
- for (j=0;j<widthout*components;j++) {
- *ubptr++ = (GLubyte) tempout[k++];
- }
- }
- break;
- case GL_BYTE:
- k = 0;
- for (i=0;i<heightout;i++) {
- GLbyte *bptr = (GLbyte *) dataout
- + i * rowstride
- + packskiprows * rowstride
- + packskippixels * components;
- for (j=0;j<widthout*components;j++) {
- *bptr++ = (GLbyte) tempout[k++];
- }
- }
- break;
- case GL_UNSIGNED_SHORT:
- k = 0;
- for (i=0;i<heightout;i++) {
- GLushort *usptr = (GLushort *) dataout
- + i * rowstride
- + packskiprows * rowstride
- + packskippixels * components;
- for (j=0;j<widthout*components;j++) {
- *usptr++ = (GLushort) tempout[k++];
- }
- }
- break;
- case GL_SHORT:
- k = 0;
- for (i=0;i<heightout;i++) {
- GLshort *sptr = (GLshort *) dataout
- + i * rowstride
- + packskiprows * rowstride
- + packskippixels * components;
- for (j=0;j<widthout*components;j++) {
- *sptr++ = (GLshort) tempout[k++];
- }
- }
- break;
- case GL_UNSIGNED_INT:
- k = 0;
- for (i=0;i<heightout;i++) {
- GLuint *uiptr = (GLuint *) dataout
- + i * rowstride
- + packskiprows * rowstride
- + packskippixels * components;
- for (j=0;j<widthout*components;j++) {
- *uiptr++ = (GLuint) tempout[k++];
- }
- }
- break;
- case GL_INT:
- k = 0;
- for (i=0;i<heightout;i++) {
- GLint *iptr = (GLint *) dataout
- + i * rowstride
- + packskiprows * rowstride
- + packskippixels * components;
- for (j=0;j<widthout*components;j++) {
- *iptr++ = (GLint) tempout[k++];
- }
- }
- break;
- case GL_FLOAT:
- k = 0;
- for (i=0;i<heightout;i++) {
- GLfloat *fptr = (GLfloat *) dataout
- + i * rowstride
- + packskiprows * rowstride
- + packskippixels * components;
- for (j=0;j<widthout*components;j++) {
- *fptr++ = tempout[k++];
- }
- }
- break;
- default:
- return GLU_INVALID_ENUM;
- }
-
-
- /* free temporary image storage */
- free( tempin );
- free( tempout );
-
- return 0;
- }
-
-
-
- /*
- * Return the largest k such that 2^k <= n.
- */
- static GLint ilog2( GLint n )
- {
- GLint k;
-
- if (n<=0) return 0;
- for (k=0; n>>=1; k++) ;
- return k;
- }
-
-
-
- /*
- * Find the value nearest to n which is also a power of two.
- */
- static GLint round2( GLint n )
- {
- GLint m;
-
- for (m=1; m<n; m*=2)
- ;
-
- /* m>=n */
- if (m-n <= n-m/2) {
- return m;
- }
- else {
- return m/2;
- }
- }
-
-
- /*
- * Given an pixel format and datatype, return the number of bytes to
- * store one pixel.
- */
- static GLint bytes_per_pixel( GLenum format, GLenum type )
- {
- GLint n, m;
-
- switch (format) {
- case GL_COLOR_INDEX:
- case GL_STENCIL_INDEX:
- case GL_DEPTH_COMPONENT:
- case GL_RED:
- case GL_GREEN:
- case GL_BLUE:
- case GL_ALPHA:
- case GL_LUMINANCE:
- n = 1;
- break;
- case GL_LUMINANCE_ALPHA:
- n = 2;
- break;
- case GL_RGB:
- n = 3;
- break;
- case GL_RGBA:
- n = 4;
- break;
- default:
- n = 0;
- }
-
- switch (type) {
- case GL_UNSIGNED_BYTE: m = sizeof(GLubyte); break;
- case GL_BYTE: m = sizeof(GLbyte); break;
- case GL_BITMAP: m = 1; break;
- case GL_UNSIGNED_SHORT: m = sizeof(GLushort); break;
- case GL_SHORT: m = sizeof(GLshort); break;
- case GL_UNSIGNED_INT: m = sizeof(GLuint); break;
- case GL_INT: m = sizeof(GLint); break;
- case GL_FLOAT: m = sizeof(GLfloat); break;
- default: m = 0;
- }
-
- return n * m;
- }
-
-
-
- /*
- * WARNING: This function isn't finished and has never been tested!!!!
- */
- GLint gluBuild1DMipmaps( GLenum target, GLint components,
- GLint width, GLenum format,
- GLenum type, const void *data )
- {
- GLubyte *texture;
- GLint levels, max_levels;
- GLint new_width, max_width;
- GLint i, j, k, l;
-
- glGetIntegerv( GL_MAX_TEXTURE_SIZE, &max_width );
- max_levels = ilog2( max_width ) + 1;
-
- /* Compute how many mipmap images to make */
- levels = ilog2( width ) + 1;
- if (levels>max_levels) {
- levels = max_levels;
- }
-
- new_width = 1 << (levels-1);
-
- texture = (GLubyte *) malloc( new_width * components );
- if (!texture) {
- return GLU_OUT_OF_MEMORY;
- }
-
- if (width != new_width) {
- /* initial rescaling */
- switch (type) {
- case GL_UNSIGNED_BYTE:
- {
- GLubyte *ub_data = (GLubyte *) data;
- for (i=0;i<new_width;i++) {
- j = i * width / new_width;
- for (k=0;k<components;k++) {
- texture[i*components+k] = ub_data[j*components+k];
- }
- }
- }
- break;
- default:
- /* Not implemented */
- return GLU_ERROR;
- }
- }
-
- /* generate and load mipmap images */
- for (l=0;l<levels;l++) {
- glTexImage1D( GL_TEXTURE_1D, l, components, new_width, 0,
- format, GL_UNSIGNED_BYTE, texture );
-
- /* Scale image down to 1/2 size */
- new_width = new_width / 2;
- for (i=0;i<new_width;i++) {
- for (k=0;k<components;k++) {
- GLint sample1, sample2;
- sample1 = (GLint) texture[i*2*components+k];
- sample2 = (GLint) texture[(i*2+1)*components+k];
- texture[i*components+k] = (GLubyte) ((sample1 + sample2) / 2);
- }
- }
- }
-
- free( texture );
-
- /* make sure remaining mipmap levels are removed */
- for (l=levels;l<max_levels;l++) {
- glTexImage1D( GL_TEXTURE_1D, l, components, 0, 0,
- format, GL_UNSIGNED_BYTE, NULL );
- }
-
- return 0;
- }
-
-
-
- GLint gluBuild2DMipmaps( GLenum target, GLint components,
- GLint width, GLint height, GLenum format,
- GLenum type, const void *data )
- {
- GLint w, h, maxsize;
- void *image, *newimage;
- GLint neww, newh, level, bpp;
- int error;
-
- glGetIntegerv( GL_MAX_TEXTURE_SIZE, &maxsize );
-
- w = round2( width );
- if (w>maxsize) {
- w = maxsize;
- }
- h = round2( height );
- if (h>maxsize) {
- h = maxsize;
- }
-
- bpp = bytes_per_pixel( format, type );
- if (bpp==0) {
- /* probably a bad format or type enum */
- return GLU_INVALID_ENUM;
- }
-
- if (w!=width || h!=height) {
- /* must rescale image to get "top" mipmap texture image */
- image = malloc( (w+4) * h * bpp );
- if (!image) {
- return GLU_OUT_OF_MEMORY;
- }
- error = gluScaleImage( format, width, height, type, data,
- w, h, type, image );
- if (error) {
- return error;
- }
- }
- else {
- image = (void *) data;
- }
-
- level = 0;
- while (1) {
- glTexImage2D( target, level, components, w, h, 0, format, type, image );
-
- if (w==1 && h==1) break;
-
- neww = (w<2) ? 1 : w/2;
- newh = (h<2) ? 1 : h/2;
- newimage = malloc( (neww+4) * newh * bpp );
- if (!newimage) {
- return GLU_OUT_OF_MEMORY;
- }
-
- error = gluScaleImage( format, w, h, type, image,
- neww, newh, type, newimage );
- if (error) {
- return error;
- }
-
- if (image!=data) {
- free( image );
- }
- image = newimage;
-
- w = neww;
- h = newh;
- level++;
- }
-
- if (image!=data) {
- free( image );
- }
-
- return 0;
- }
-
-